#include "ftp_server.h"

extern int terminate;
// 服务器的共享的“目录”
char FTP_ROOT_DIR[128] = "/home/china/ftp";
static sqlite3 *ppDb; // 保存数据库链接对象
/*
sighandler:信号处理函数
sig:具体的信号值
返回值:
    无
*/
void sighandler(int sig)
{
    switch (sig)
    {
    // Ctrl +C
    case SIGINT:
        terminate = 1;
        break;
    // 当子进程终止或者退出时，父进程就会收到SIGCHLD
    case SIGCHLD:
        wait(NULL); // 阻塞的函数(回收子进程资源)
        break;
    }
}
/*
make_tcp_server:用来创建并且初始化一个TCP服务器
@ip:你创建的服务器绑定的IP地址
@port:你创建的服务器绑定的端口号
@listen_num:最大监听数量
返回值:
    成功返回创建好的套接字描述符
    失败返回-1,报错
*/
int make_tcp_server(const char *ip, unsigned short port)
{
    // 创建一个TCP套接字
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    if (-1 == sock)
    {
        perror("socket error");
        return -1;
    }

    // 设置服务器IP和端口号
    // a.描述一个服务器地址
    struct sockaddr_in saddr;
    memset(&saddr, 0, sizeof(saddr));
    saddr.sin_family = AF_INET;       // 设置地址协议族
    saddr.sin_port = htons(port);     // 端口号
    inet_aton(ip, &(saddr.sin_addr)); // ip

    // 设置端口重用
    int n = 1;
    setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &n, sizeof(n));

    // b.绑定,把一个指定的网络地址绑定到sock
    int r = bind(sock, (struct sockaddr *)&saddr, sizeof(saddr));
    if (-1 == r)
    {
        perror("bind error");
        return -1;
    }
    printf("bind success !\n");

    // 开启对套接字的监听
    r = listen(sock, MAX_LISTEN); // MAX_LISTEN：128
    if (r == -1)
    {
        fprintf(stderr, "Error in listen function, server failed to create socket queue\n");
        close(sock);
        return -1;
    }
    printf("listen success !\n");

    // 返回初始化好的套接字描述符
    printf("init TCP server success!\n");
    return sock;
}

/*
handle_connection:处理和客户端的通信
confd:和客户端通信的连接套接字
返回值:
    无
*/
void handle_connection(int confd, struct CLI_INFO *ap)
{
    // 处理客户端登录
    while (resp_login_db(confd) != 1)
        ;

    unsigned char cmd[1024] = {0};
    int i = 0;
    while (1)
    {
        memset(cmd, 0, 1024);
        // 读取客户端发送给我的命令(按照协议读取数据)
        // 找到第一个0xc0(用户数据中不能出现0xc0)
        int r;
        unsigned char ch;
        do
        {
            r = read(confd, &ch, 1);
            if (r <= 0)
            {
                exit(0);
            }
        } while (ch != 0xc0);

        // 防止上一次遗留的数据包的包尾
        while (ch == 0xc0)
        {
            r = read(confd, &ch, 1);
            if (r <= 0)
            {
                exit(0);
            }
        }
        // ch肯定不是0xc0,是数据包中的第一个有效字节
        i = 0;
        while (ch != 0xc0) // 一次性把数据包读取到cmd中
        {
            cmd[i++] = ch;
            read(confd, &ch, 1);
        }
        // 做一个简单的校验(数据包长度校验)
        int pkg_len = (cmd[0] & 0xff) | ((cmd[1] & 0xff) << 8) |
                      ((cmd[2] & 0xff) << 16) | ((cmd[3] & 0xff) << 24);
        if (i != pkg_len) // 读取到的实际长度和理论长短不一样,直接丢弃
        {
            printf("pkg_len = %d,i = %d\n", pkg_len, i);
            continue;
        }

        // 解析命令号,根据命令号去解析剩下的参数
        int cmd_no = (cmd[4] & 0xff) | ((cmd[5] & 0xff) << 8) |
                     ((cmd[6] & 0xff) << 16) | ((cmd[7] & 0xff) << 24);

        // 根据命令号做相应的回复
        if (cmd_no == FTP_CMD_LS) // ls
        {
            // 回复客户端的LS请求
            resp_ls(confd, FTP_ROOT_DIR);
        }
        else if (cmd_no == FTP_CMD_GET) // get
        {
            // 读取客户端需要的文件名
            // 0xc0  pkg_len cmd_no arg_1_len arg_1_data(filename) 0xc0
            char filename[256] = {0};
            int arg_1_len = (cmd[8] & 0xff) | ((cmd[9] & 0xff) << 8) |
                            ((cmd[10] & 0xff) << 16) | ((cmd[11] & 0xff) << 24);
            int j = 0;
            for (j = 0; j < arg_1_len; j++)
            {
                filename[j] = cmd[12 + j];
            }
            // 回复客户端的请求
            printf("arg_1_len:%d\n", arg_1_len);
            printf("get file:%s\n", filename);
            resp_get(confd, filename);
        }
        else if (cmd_no == FTP_CMD_GET_FOLDER) // get a folder
        {
            // 读取客户端需要的文件名
            // 0xc0  pkg_len cmd_no arg_1_len arg_1_data(filename) 0xc0
            char foldername[256] = {0};
            int arg_1_len = (cmd[8] & 0xff) | ((cmd[9] & 0xff) << 8) |
                            ((cmd[10] & 0xff) << 16) | ((cmd[11] & 0xff) << 24);
            int j = 0;
            for (j = 0; j < arg_1_len; j++)
            {
                foldername[j] = cmd[12 + j];
            }
            // 回复客户端的请求
            printf("arg_1_len:%d\n", arg_1_len);
            printf("get_folder file:%s\n", foldername);
            resp_get_folder(confd, foldername);
        }
        else if (cmd_no == FTP_CMD_PUT) // put
        {
            // 读取客户端需要推送的文件名和文件大小
            // 0xc0  pkg_len cmd_no arg_1_len arg_1_data(filename) arg_1_data2(filesize) 0xc0
            char filename[256] = {0};
            int arg_1_len = (cmd[8] & 0xff) | ((cmd[9] & 0xff) << 8) |
                            ((cmd[10] & 0xff) << 16) | ((cmd[11] & 0xff) << 24);
            int j = 0;
            for (j = 0; j < arg_1_len; j++)
            {
                filename[j] = cmd[12 + j];
            }
            printf("put file:%s\n", filename);
            // 获取文件大小
            int filesize = (cmd[12 + j] & 0xff) | ((cmd[13 + j] & 0xff) << 8) |
                           ((cmd[14 + j] & 0xff) << 16) | ((cmd[15 + j] & 0xff) << 24);
            printf("put file_size:%d\n", filesize);
            // 接收文件的所有的内容
            resp_put(confd, filename, filesize); // 仅仅是接受filesize个字节的内容存储到filename表示的文件
        }
        else if (cmd_no == FTP_CMD_BYE) // bye
        {
            // 把客户端信息和资源都回收
            printf("disconnect client IP:%s,client Port:%d\n", ap->ip, ap->port);
            close(confd);
            exit(0);
        }
        else if (cmd_no == FTP_CMD_RM) // rm
        {
            // 读取客户端需要删除的文件名
            // 0xc0  pkg_len cmd_no arg_1_len arg_1_data(filename) 0xc0
            char filename[256] = {0};
            int arg_1_len = (cmd[8] & 0xff) | ((cmd[9] & 0xff) << 8) |
                            ((cmd[10] & 0xff) << 16) | ((cmd[11] & 0xff) << 24);
            int j = 0;
            for (j = 0; j < arg_1_len; j++)
            {
                filename[j] = cmd[12 + j];
            }
            // 回复客户端的请求
            printf("arg_1_len:%d\n", arg_1_len);
            printf("get file:%s\n", filename);
            resp_rm(confd, filename);
        }
        else if (cmd_no == FTP_CMD_CD)
        {
            // 读取客户端需要进入的目录名
            // 0xc0  pkg_len cmd_no arg_1_len arg_1_data(filename) 0xc0
            char filename[256] = {0};
            int arg_1_len = (cmd[8] & 0xff) | ((cmd[9] & 0xff) << 8) |
                            ((cmd[10] & 0xff) << 16) | ((cmd[11] & 0xff) << 24);
            int j = 0;
            for (j = 0; j < arg_1_len; j++)
            {
                filename[j] = cmd[12 + j];
            }
            char *s = resp_cd(confd, filename);
            strcpy(FTP_ROOT_DIR, s);
            printf("%s\n", FTP_ROOT_DIR);
        }
        else if (cmd_no == FTP_CMD_PWD)
        {
            resp_pwd(confd);
        }
    }
}

/*
resp_ls:回复客户端的ls请求
confd:和客户端通信的连接套接字
返回值:
    无
*/
void resp_ls(int confd, char *filename)
{
    // 0xc0  pkg_len(4) cmd_no(4) resp_len(4) result(1) resp_conent(x) 0xc0
    unsigned char filelist[4096] = {0}; // 保存了服务器目录中的文件列表
    int result = 0;                     // 假设获取文件名成功

    DIR *dir = opendir(filename); // 获取文件名列表(打开目录/获取文件名列表)
    if (dir == NULL)
    {
        perror("opendir error");
        result = 1; // 失败
    }
    struct dirent *dirp = NULL;
    int r = 0;
    while (dirp = readdir(dir))
    {
        // 过滤.和..
        if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
        {
            continue;
        }

        r += sprintf(filelist + r, "%s  ", dirp->d_name);
    }

    // 准备回复数据包
    unsigned char resp[8192] = {0};
    // 构造数据包前,要提前准备好文件名(文件IO读目录,把目录中的文件名放到filelist中)
    int x = (result == 0) ? strlen(filelist) : 4; // 所有文件列表的长度
    int pkg_len = 4 + 4 + 4 + 1 + x;              // 整个数据包的长度
    int cmd_no = FTP_CMD_LS;
    int resp_len = 1 + x;

    int i = 0;
    resp[i++] = 0xc0; // 包头
    // pkg_len
    resp[i++] = pkg_len & 0xff; // 第一个字节(低字节) pkg_len
    resp[i++] = (pkg_len >> 8) & 0xff;
    resp[i++] = (pkg_len >> 16) & 0xff;
    resp[i++] = (pkg_len >> 24) & 0xff;
    // cmd_no(4)
    resp[i++] = cmd_no & 0xff; // 第一个字节(低字节) pkg_len
    resp[i++] = (cmd_no >> 8) & 0xff;
    resp[i++] = (cmd_no >> 16) & 0xff;
    resp[i++] = (cmd_no >> 24) & 0xff;
    // resp_len(4)
    resp[i++] = resp_len & 0xff; // 第一个字节(低字节) pkg_len
    resp[i++] = (resp_len >> 8) & 0xff;
    resp[i++] = (resp_len >> 16) & 0xff;
    resp[i++] = (resp_len >> 24) & 0xff;
    // result(1)
    resp[i++] = result;
    // resp_conent(x)
    if (result == 1) // 失败发送错误码
    {
        resp[i++] = errno & 0xff; // 第一个字节(低字节) pkg_len
        resp[i++] = (errno >> 8) & 0xff;
        resp[i++] = (errno >> 16) & 0xff;
        resp[i++] = (errno >> 24) & 0xff;
    }
    else // 成功发送文件名列表
    {
        // strncpy(cmd+i,filelist,x)
        // cmd[i+x] = 0xc0;
        int j;
        for (j = 0; j < x; j++)
        {
            resp[i++] = filelist[j];
        }
    }
    // 0xc0
    resp[i++] = 0xc0;
    // 发送给客户端
    write(confd, resp, i);
}

/*
resp_get:回复客户端的get请求
confd:和客户端通信的连接套接字
filename:客户端需要获取的文件名
返回值:
    无
*/

void resp_get(int confd, char *filename)
{
    // 发送数据包给客户端,告诉客户端需要获取的文件的大小
    //(1).0xc0  pkg_len(4) cmd_no(4) resp_len(4) result(1) resp_conent(filesize) 0xc0
    // 准备回复数据包
    unsigned char resp[20] = {0}; // 回复数据包
    char result = 0;              // 假设获取成功
    // 找到共享目录中对应的文件,获取文件大小
    unsigned char pathname[256] = {0};
    snprintf(pathname, 256, "%s/%s", FTP_ROOT_DIR, filename);
    struct stat st;
    int r = lstat(pathname, &st);
    if (r == -1)
    {
        result = 1; // 告诉客户端,过去失败
        perror("resp_get lstat failed");
    }
    int file_size = st.st_size;
    int pkg_len = 4 + 4 + 4 + 1 + 4; // 整个数据包的长度
    int cmd_no = FTP_CMD_GET;
    int resp_len = 1 + 4; // 文件列表的长度，1为错误码长 ，4为文件长，因为为获取一个长

    int i = 0;
    resp[i++] = 0xc0; // 包头
    // pkg_len
    resp[i++] = pkg_len & 0xff; // 第一个字节(低字节) pkg_len
    resp[i++] = (pkg_len >> 8) & 0xff;
    resp[i++] = (pkg_len >> 16) & 0xff;
    resp[i++] = (pkg_len >> 24) & 0xff;
    // cmd_no(4)
    resp[i++] = cmd_no & 0xff; // 第一个字节(低字节) pkg_len
    resp[i++] = (cmd_no >> 8) & 0xff;
    resp[i++] = (cmd_no >> 16) & 0xff;
    resp[i++] = (cmd_no >> 24) & 0xff;
    // resp_len(4)
    resp[i++] = resp_len & 0xff; // 第一个字节(低字节) pkg_len
    resp[i++] = (resp_len >> 8) & 0xff;
    resp[i++] = (resp_len >> 16) & 0xff;
    resp[i++] = (resp_len >> 24) & 0xff;
    // result(1)
    resp[i++] = result;
    // resp_conent(x)
    if (result == 1) // 失败发送错误码
    {
        resp[i++] = errno & 0xff; // 第一个字节(低字节) pkg_len
        resp[i++] = (errno >> 8) & 0xff;
        resp[i++] = (errno >> 16) & 0xff;
        resp[i++] = (errno >> 24) & 0xff;
    }
    else // 成功发送文件大小
    {
        resp[i++] = file_size & 0xff; // 第一个字节(低字节) pkg_len
        resp[i++] = (file_size >> 8) & 0xff;
        resp[i++] = (file_size >> 16) & 0xff;
        resp[i++] = (file_size >> 24) & 0xff;
    }
    // 0xc0
    resp[i++] = 0xc0;
    // 发送给客户端
    write(confd, resp, i);

    //(2).文件的所有内容
    if (result == 0)
    {
        FILE *fp = fopen(pathname, "r");
        if (NULL == fp)
        {
            perror("resp_get:fopen error");
            return;
        }
        unsigned char buf[1024] = {0};
        while (1)
        {
            memset(buf, 0, 1024);
            size_t r = fread(buf, 1, 1024, fp);
            if (r > 0)
            {
                write(confd, buf, r);
            }
            else if (r == 0)
            {
                break;
            }
            else
            {
                perror("resp_get:fread error");
                break;
            }
        }
        fclose(fp);
    }
}

void resp_get_folder(int confd, char *folder_path)
{
    // 发送数据包给客户端,告诉客户端需要获取的文件的大小
    //(1).0xc0  pkg_len(4) cmd_no(4) resp_len(4) result(1) resp_conent(filesize) 0xc0
    // 准备回复数据包
    unsigned char resp[20] = {0}; // 回复数据包
    char result = 0;              // 假设获取成功
    // 找到共享目录中对应的文件,获取文件大小
    unsigned char pathname[256] = {0};
    snprintf(pathname, 256, "%s/%s", FTP_ROOT_DIR, folder_path);
    struct stat st;
    int r = lstat(pathname, &st);
    if (r == -1)
    {
        result = 1; // 告诉客户端,过去失败
        perror("resp_get lstat failed");
    }
    int file_size = st.st_size;
    int pkg_len = 4 + 4 + 4 + 1 + 4; // 整个数据包的长度
    int cmd_no = FTP_CMD_GET_FOLDER;
    int resp_len = 1 + 4;

    int i = 0;
    resp[i++] = 0xc0; // 包头
    // pkg_len
    resp[i++] = pkg_len & 0xff; // 第一个字节(低字节) pkg_len
    resp[i++] = (pkg_len >> 8) & 0xff;
    resp[i++] = (pkg_len >> 16) & 0xff;
    resp[i++] = (pkg_len >> 24) & 0xff;
    // cmd_no(4)
    resp[i++] = cmd_no & 0xff; // 第一个字节(低字节) pkg_len
    resp[i++] = (cmd_no >> 8) & 0xff;
    resp[i++] = (cmd_no >> 16) & 0xff;
    resp[i++] = (cmd_no >> 24) & 0xff;
    // resp_len(4)
    resp[i++] = resp_len & 0xff; // 第一个字节(低字节) pkg_len
    resp[i++] = (resp_len >> 8) & 0xff;
    resp[i++] = (resp_len >> 16) & 0xff;
    resp[i++] = (resp_len >> 24) & 0xff;
    // result(1)
    resp[i++] = result;
    // resp_conent(x)
    if (result == 1) // 失败发送错误码
    {
        resp[i++] = errno & 0xff; // 第一个字节(低字节) pkg_len
        resp[i++] = (errno >> 8) & 0xff;
        resp[i++] = (errno >> 16) & 0xff;
        resp[i++] = (errno >> 24) & 0xff;
    }
    else // 成功发送文件夹大小
    {
        resp[i++] = file_size & 0xff; // 第一个字节(低字节) pkg_len
        resp[i++] = (file_size >> 8) & 0xff;
        resp[i++] = (file_size >> 16) & 0xff;
        resp[i++] = (file_size >> 24) & 0xff;
    }
    // 0xc0
    resp[i++] = 0xc0;
    // 发送给客户端
    write(confd, resp, i);

    //(2).文件的所有内容
    // 打开文件夹
    DIR *folder = opendir(pathname);
    // 遍历文件夹内容
    struct dirent *entry;
    while ((entry = readdir(folder)) != NULL)
    {
        // 忽略当前目录和上一级目录
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        {
            continue;
        }
        char destinationPath[1024] = {0};
        snprintf(destinationPath, 1024, "%s/%s", pathname, entry->d_name);
        printf("%d %s\n", __LINE__, destinationPath);
        // // 如果是文件，则复制文件
        if (entry->d_type == DT_REG)
        {
            if (result == 0)
            {
                FILE *fp = fopen(destinationPath, "r+");
                if (NULL == fp)
                {
                    perror("resp_get:fopen error");
                    return;
                }
                struct
                {
                    unsigned char buf[128];
                    int file_size;
                } tmp;
                memset(&tmp, 0, sizeof(tmp));

                lstat(destinationPath, &st);
                tmp.file_size = st.st_size;
                printf("tmp.file_size:%d\n", tmp.file_size);
                strcpy(tmp.buf, entry->d_name);
                printf("%s\n", tmp.buf);
                // 把文件名，和单个文件大小发过去
                write(confd, &tmp, sizeof(tmp));
                int cur_read = 0;
                while (cur_read < tmp.file_size)
                {
                    unsigned char buf[128];
                    memset(&tmp.buf, 0, 128);
                    size_t r = fread(buf, 1, 128, fp);
                    if (r > 0)
                    {
                        write(confd, buf, r);
                    }
                    else if (r == 0)
                    {
                        break;
                    }
                    else
                    {
                        perror("resp_get:fread error");
                        break;
                    }
                }
                fclose(fp);
            }
        }
        // 如果是目录，则继续递归复制目录
        else if (entry->d_type == DT_DIR)
        {
            resp_get_folder(confd, destinationPath);
        }
    }
    closedir(folder);
}

/*
resp_put:回复客户端的put请求(读取推送文件的数据)
confd:和客户端通信的连接套接字
filename:客户端需要推送的文件名
@filesize:上传文件大小
返回值:
    无
*/
void resp_put(int confd, char *filename, int filesize)
{
    unsigned char resp[20] = {0}; // 回复数据包
    char result = 0;              // 假设上传成功
    unsigned char pathname[256] = {0};
    snprintf(pathname, 256, "%s/%s", FTP_ROOT_DIR, filename);

    // 准备回复数据包
    int pkg_len = 4 + 4 + 4 + 1;
    int cmd_no = FTP_CMD_PUT;
    int resp_len = 1;

    int i = 0;
    resp[i++] = 0xc0; // 包头
    // pkg_len
    resp[i++] = pkg_len & 0xff;
    resp[i++] = (pkg_len >> 8) & 0xff;
    resp[i++] = (pkg_len >> 16) & 0xff;
    resp[i++] = (pkg_len >> 24) & 0xff;
    // cmd_no(4)
    resp[i++] = cmd_no & 0xff;
    resp[i++] = (cmd_no >> 8) & 0xff;
    resp[i++] = (cmd_no >> 16) & 0xff;
    resp[i++] = (cmd_no >> 24) & 0xff;
    // resp_len(4)
    resp[i++] = resp_len & 0xff;
    resp[i++] = (resp_len >> 8) & 0xff;
    resp[i++] = (resp_len >> 16) & 0xff;
    resp[i++] = (resp_len >> 24) & 0xff;
    // result(1)
    resp[i++] = result;

    // 0xc0
    resp[i++] = 0xc0;

    // 发送给客户端
    write(confd, resp, i);

    // 接收文件内容并保存
    FILE *fp = fopen(pathname, "w");
    if (NULL == fp)
    {
        perror("resp_put:fopen error");
        return;
    }
    int cur_read = 0;
    while (cur_read < filesize)
    {
        unsigned char buf[1024] = {0};
        int r = read(confd, buf, 1024);
        if (r > 0)
        {
            cur_read += r;
            fwrite(buf, 1, r, fp);
        }
    }
    fclose(fp);
}

/*
resp_rm:回复客户端的rm请求,删除一个普通文件
filename:客户端需要删除的文件名
返回值:
    无
*/
void resp_rm(int confd, char *filename)
{
    // 按照私有协议给服务器发送请求
    // 0xc0  pkg_len cmd_no arg_1_len arg_1_data(arg_1_len) 0xc0

    unsigned char resp[20] = {0}; // 回复数据包
    char result = 0;              // 假设RM成功
    unsigned char pathname[256] = {0};
    snprintf(pathname, 256, "%s/%s", FTP_ROOT_DIR, filename);
    // 目标文件不存在
    if (fopen(pathname, "r") == NULL)
    {
        result = 1; // 文件不不存在
        perror("opendir error");
    }
    // 准备回复数据包
    int pkg_len = 4 + 4 + 4 + 1;
    int cmd_no = FTP_CMD_CD;
    int resp_len = 1;

    int i = 0;
    resp[i++] = 0xc0; // 包头
    // pkg_len(4)
    resp[i++] = pkg_len & 0xff;
    resp[i++] = (pkg_len >> 8) & 0xff;
    resp[i++] = (pkg_len >> 16) & 0xff;
    resp[i++] = (pkg_len >> 24) & 0xff;
    // cmd_no(4)
    resp[i++] = cmd_no & 0xff;
    resp[i++] = (cmd_no >> 8) & 0xff;
    resp[i++] = (cmd_no >> 16) & 0xff;
    resp[i++] = (cmd_no >> 24) & 0xff;
    // resp_len(4)
    resp[i++] = resp_len & 0xff;
    resp[i++] = (resp_len >> 8) & 0xff;
    resp[i++] = (resp_len >> 16) & 0xff;
    resp[i++] = (resp_len >> 24) & 0xff;
    // result(1)
    resp[i++] = result;
    // 0xc0
    resp[i++] = 0xc0; // 包尾
    int ret = write(confd, resp, i);
    if (ret != i)
    {
        printf("send command failed!\n");
        return;
    }
    int re = unlink(pathname);
    if (re == 0)
    {
        printf("unlink a file: %s\n", filename);
    }
    else
    {
        perror("unlink error");
        return;
    }
}

/*
resp_cd:回复客户端的cd请求,进入一个目录
filename:客户端需要进入的那个目录
返回值:
    无
*/

char *resp_cd(int confd, char *filename)
{
    // 按照私有协议给服务器发送请求
    // 0xc0  pkg_len cmd_no arg_1_len arg_1_data(arg_1_len) 0xc0

    unsigned char resp[20] = {0}; // 回复数据包
    char result = 0;              // 假设CD成功
    unsigned char pathname[256] = {0};
    snprintf(pathname, 256, "%s/%s", FTP_ROOT_DIR, filename);
    // 目标文件夹不存在
    if (opendir(pathname) == NULL)
    {
        result = 1; // 目录不存在
        perror("opendir error");
    }
    // 准备回复数据包
    int pkg_len = 4 + 4 + 4 + 1;
    int cmd_no = FTP_CMD_CD;
    int resp_len = 1;

    int i = 0;
    resp[i++] = 0xc0; // 包头
    // pkg_len(4)
    resp[i++] = pkg_len & 0xff;
    resp[i++] = (pkg_len >> 8) & 0xff;
    resp[i++] = (pkg_len >> 16) & 0xff;
    resp[i++] = (pkg_len >> 24) & 0xff;
    // cmd_no(4)
    resp[i++] = cmd_no & 0xff;
    resp[i++] = (cmd_no >> 8) & 0xff;
    resp[i++] = (cmd_no >> 16) & 0xff;
    resp[i++] = (cmd_no >> 24) & 0xff;
    // resp_len(4)
    resp[i++] = resp_len & 0xff;
    resp[i++] = (resp_len >> 8) & 0xff;
    resp[i++] = (resp_len >> 16) & 0xff;
    resp[i++] = (resp_len >> 24) & 0xff;
    // result(1)
    resp[i++] = result;
    // 0xc0
    resp[i++] = 0xc0; // 包尾
    int ret = write(confd, resp, i);
    if (ret != i)
    {
        printf("send command failed!\n");
        return NULL;
    }

    memset(pathname, 0, 256);
    snprintf(pathname, 256, "%s/%s", FTP_ROOT_DIR, filename);

    int re = chdir(pathname); // 切换目录
    if (re == 0)
    {
        printf("chdir  dir to %s\n", filename);
        char buf[128];
        memset(buf, 0, 128);
        getcwd(buf, 128);
        printf("%s\n", buf);
        strcpy(filename, buf);
        return filename;
    }
    else
    {
        perror("chdir error");
        return NULL;
    }
}

/*
resp_pwd:回复客户端的pwd请求
confd:和客户端通信的连接套接字
返回值:
    无
*/
char *resp_pwd(int confd)
{
    unsigned char resp[20] = {0}; // 回复数据包
    // 准备回复数据包
    int pkg_len = 4 + 4 + 1;
    int cmd_no = FTP_CMD_PWD;
    int result = 0; // 假设回复成功

    int i = 0;
    // 0xc0
    resp[i++] = 0xc0; // 包头
    // pkg_len(4)
    resp[i++] = pkg_len & 0xff;
    resp[i++] = (pkg_len >> 8) & 0xff;
    resp[i++] = (pkg_len >> 16) & 0xff;
    resp[i++] = (pkg_len >> 24) & 0xff;
    // cmd_no(4)
    resp[i++] = cmd_no & 0xff;
    resp[i++] = (cmd_no >> 8) & 0xff;
    resp[i++] = (cmd_no >> 16) & 0xff;
    resp[i++] = (cmd_no >> 24) & 0xff;
    // result(1)
    resp[i++] = result;
    // 0xc0
    resp[i++] = 0xc0; // 包尾
    int ret = write(confd, resp, i);
    if (ret != i)
    {
        printf("send command failed!\n");
        return NULL;
    }
    char buf[128];
    memset(buf, 0, 128);
    chdir(FTP_ROOT_DIR);
    getcwd(buf, 128);
    int w = write(confd, buf, strlen(buf));
}

/*
foundUser:查找文件中用户名
@usernaem：用户名
@file文件指针
返回值:
    查找到返回      1
    未查找到返回    0
*/
int foundUser(const char *username, FILE *file)
{
    char usr[20];
    int found = 0;
    while (fscanf(file, "%s", usr) != EOF)
    {
        if (strcmp(usr, username) == 0)
        {
            found = 1;
            return found; // 找到
        }
    }
    return found; // 未找到
}

/*
resp_login:响应客户端登录服务器
@confd:通信的socket套接字
返回值：
    无
*/
int resp_login(int confd)
{
    struct ftplogin login;
    memset(&login, 0, sizeof(login));
    char buf[20];
    int ret;
    char username[20], password[20];
    ret = read(confd, &login, sizeof(login)); // 获取客户端的登录信息
    if (ret == -1)
    {
        perror("read error");
        return -1;
    }
    // 打开文件
    FILE *file = fopen("users.txt", "a+");
    // 先去文件中查找用户名，如果不存在则发送信息给客户端提示是否注册
    if (foundUser(login.usr, file) != 1)
    {
        memset(buf, 0, 20);
        strcpy(buf, "Not Found");
        write(confd, buf, 20);
        printf("等待用户回应......\n");
        sleep(4);
        memset(buf, 0, 20);
        read(confd, buf, 20);
        if (strcmp(buf, "YES") == 0)
        {
            // 写入文件
            fprintf(file, "%s %s\n", login.usr, login.pwd);
            printf("用户注册成功\n");
            fclose(file);
            return 1;
        }
        else
        {
            return -1;
        }
    }
    file = fopen("users.txt", "r");
    // 逐行读取文件，查找匹配的用户名和密码
    while (fscanf(file, "%s %s", username, password) != EOF)
    {

        if (strcmp(username, login.usr) == 0 && strcmp(password, login.pwd) == 0)
        {
            printf("%d\n", __LINE__);
            memset(buf, 0, 20);
            strcpy(buf, "OK");
            write(confd, buf, 20);
            // 关闭文件
            fclose(file);
            return 1;
        }
        else
        {
            memset(buf, 0, 20);
            strcpy(buf, "NO");
            write(confd, buf, 20);
        }
    }
    return -1;
}
/*
resp_login_db:数据库实现保存用户名和密码
@confd:通信的socket套接字
返回值:
    无
*/

/*
verify_username_password:验证用户名和密码，如果正确返回true, 否则返回false
@username：用户名
@password：密码
*/
bool verify_username_password(const char *username, const char *password)
{
    char sql[1024] = {0};
    sprintf(sql, "select username, password from user where username='%s' and password='%s';", username, password);

    bool ok = false;
    char *errmsg;
    int ret = sqlite3_exec(ppDb, sql, callback_verify_username_password, (void *)&ok, &errmsg);
    if (ret != SQLITE_OK)
    {
        fprintf(stderr, "verify_card_id_passwd error: %s\n", errmsg);
        sqlite3_free(errmsg);
        return false;
    }
    return ok;
}

/*
callback_verify_username_password:回调函数-验证用户名和密码
@arg: 用户传入的数据
@size:结果中有多少列
@column_values:每一列的数据（所有的值都是char *）
@header:每一列的列名（字段名）
*/
int callback_verify_username_password(void *arg, int size, char **column_values, char **header)
{

    printf("username:%s\n", column_values[0]);
    printf("password:%s\n", column_values[1]);
    *(bool *)arg = true; // 查到
    return 0;
}

int resp_login_db(int confd)
{
    struct ftplogin login;
    memset(&login, 0, sizeof(login));
    char buf[20];
    int ret;
    char username[20], password[20];
    ret = read(confd, &login, sizeof(login)); // 获取客户端的登录信息
    if (ret == -1)
    {
        perror("read error");
        return -1;
    }
    /*--------------------------------------------------------------------------------*/
    // 打开数据库
    // 1.创建并打开一个数据库链接对象
    ret = sqlite3_open("./db/user.db", &ppDb);
    if (ret != SQLITE_OK)
    {
        printf("sqlite3_open error : %s\n", sqlite3_errmsg(ppDb));
        return -1;
    }
    // 2.创建SQL语句对象
    char sql[1024] = {0};
    sprintf(sql, "INSERT INTO user (username, password) VALUES('%s','%s');", login.usr, login.pwd);

    sqlite3_stmt *ppStmt; // 保存SQL语句对象
    const char *pzTail;

    ret = sqlite3_prepare_v2(ppDb, sql, -1, &ppStmt, &pzTail); // 创建SQL语句对象
    if (ret != SQLITE_OK)
    {
        printf("sqlite3_prepare_v2 error : %s\n", sqlite3_errmsg(ppDb));
        sqlite3_close(ppDb);
        return -1;
    }
    /*--------------------------------------------------------------------------------*/
    // 打开文件
    FILE *file = fopen("users.txt", "a+");
    // 先去文件中查找用户名，如果不存在则发送信息给客户端提示是否注册
    if (foundUser(login.usr, file) != 1)
    {
        memset(buf, 0, 20);
        strcpy(buf, "Not Found");
        write(confd, buf, 20);
        printf("等待用户回应......\n");
        sleep(3);
        memset(buf, 0, 20);
        read(confd, buf, 20);
        if (strcmp(buf, "YES") == 0 || strcmp(buf, "yes") == 0 || strcmp(buf, "y") == 0)
        {
            // 写入文件
            fprintf(file, "%s %s\n", login.usr, login.pwd);
            // 3.执行SQL语句对象
            ret = sqlite3_step(ppStmt);
            if (ret != SQLITE_DONE)
            {
                printf("sqlite3_step error : %s\n", sqlite3_errmsg(ppDb));
                sqlite3_close(ppDb);
                return -1;
            }
            printf("用户注册成功\n");
            fclose(file);
            // 4.销毁SQL语句对象
            sqlite3_finalize(ppStmt);

            // 5.关闭一个数据库链接对象
            sqlite3_close(ppDb);
            return 1;
        }
        else
        {
            return -1;
        }
    }
    ret = sqlite3_open("./db/user.db", &ppDb);

    if (verify_username_password(login.usr, login.pwd))
    {
        memset(buf, 0, 20);
        strcpy(buf, "OK");
        write(confd, buf, 20);
        // 5.关闭一个数据库链接对象
        sqlite3_close(ppDb);
        return 1;
    }
    else
    {
        memset(buf, 0, 20);
        strcpy(buf, "NO");
        write(confd, buf, 20);
    }
    return -1;
}